package cate.game.play.skill.effect.base;

import cate.common.table.d.GD;
import cate.common.table.d.GDCamp;
import cate.common.table.d.GDHero;
import cate.common.table.d.GDSkill;
import cate.game.attr.FightAttr;
import cate.game.play.config.PlayCfgArgs;
import cate.game.play.fighter.Fighter;
import cate.game.play.proce.action.ctx.SkillActionCtx;
import cate.game.play.proce.stat.ActionStat;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;

@NoteClass("伤害技能SE")
public abstract class HurtHpSE extends HpSE {

    @NoteField("技能性质")
    private byte nature;

    protected byte getNature() {
        return parent.getNature() != null ? parent.getNature() : nature;
    }

    @Override
    protected void parseArgs(PlayCfgArgs args) {
        if (nature == GDSkill.Nature.NULL) {
            nature = args.getByte("技能性质", GDSkill.Nature.NULL);
        }
    }

    /**
     * 基础伤害缩放系数
     *
     * @param actor
     * @param target
     * @param actorAttr
     * @param targetAttr
     * @param nature
     * @return
     */
    protected double baseRate(Fighter actor, Fighter target, FightAttr actorAttr, FightAttr targetAttr, byte nature) {
        double rate = 1.0;
        rate *= calBaseRate(actorAttr, targetAttr);
        rate *= calNatureRate(actorAttr, targetAttr, nature);
        rate *= calJobRate(actor.getJob(), target.getJob(), actorAttr, targetAttr);
        rate *= calCampRate(actor.getCamp(), target.getCamp(), actorAttr, targetAttr);
        return rate;
    }


    /**
     * 防御伤害减免(旧版)
     *
     * @param targetLevel
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    public double calDefRate(int targetLevel, FightAttr actorAttr, FightAttr targetAttr) {
        targetLevel = Math.min(targetLevel, 430);
        double defIgn = Math.max(0, actorAttr.penetrate() - targetAttr.penetrateDef()) / GD.W_10000_0;
        double defVal = targetAttr.defTotal() * (1 - defIgn);
        return 0.5 + (1519.5 - 3.5 * targetLevel) / (defVal + 3770);
    }


    /**
     * 新版防御公式
     *
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    public double calDefRateNew(FightAttr actorAttr, FightAttr targetAttr) {
        double tarDef = targetAttr.defTotal();
        //分段计算，第1段，计算穿透作用
        double temp1 = tarDef * (1 - actorAttr.penetrate() / GD.W_10000_0 + targetAttr.penetrateDef() / GD.W_10000_0);
        if (temp1 < 0) {
            temp1 = 0;
        } else if (temp1 > tarDef) {
            temp1 = tarDef;
        }
        //第2段，计算dr补偿，实现修改前后体验的接近。
        double temp2 = temp1 * 0.01;
        if (temp2 > 84) {
            temp2 = 84;
        }
        double temp3 = 0.000000122 * temp2 * temp2 * temp2 - 0.0000168 * temp2 * temp2 - 0.000951 * temp2 + 0.1259;
        //第3段，计算dr
        double dr = temp1 / (temp1 + 8000) + temp3;
        if (dr > 0.8) {
            dr = 0.8;
        }
        return 1 - dr;
    }


    /**
     * 基础伤害加深和减免系数
     *
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    private double calBaseRate(FightAttr actorAttr, FightAttr targetAttr) {
        double damageAddSum = actorAttr.damageAdd();
        double hurtIgnSum = targetAttr.hurtIgn();
        double rate = (damageAddSum - hurtIgnSum) / GD.W_10000_0;
        return 1.0 + Math.max(-0.6, rate);
    }

    /**
     * 对技能性质的加深或减免
     *
     * @param actorAttr
     * @param targetAttr
     * @param nature
     * @return
     */
    private double calNatureRate(FightAttr actorAttr, FightAttr targetAttr, byte nature) {
        double damageAddSum = 0d;
        double hurtIgnSum = 0d;
        double hurtAddSum = 0d;
        switch (nature) {
            case GDSkill.Nature.PHY:
                damageAddSum += actorAttr.damageAddPhy();
                hurtIgnSum += targetAttr.hurtIgnPhy();
                break;
            case GDSkill.Nature.MAGIC:
                damageAddSum += actorAttr.damageAddMagic();
                hurtIgnSum += targetAttr.hurtIgnMagic();
                break;
            default:
                break;
        }
        double rate = (damageAddSum - hurtIgnSum + hurtAddSum) / GD.W_10000_0;
        return 1.0 + Math.max(-0.6, rate);
    }

    /**
     * 职业伤害系数
     *
     * @param actorJob
     * @param targetJob
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    private double calJobRate(byte actorJob, byte targetJob, FightAttr actorAttr, FightAttr targetAttr) {
        double damageAddSum = 0;
        double hurtIgnSum = 0;
        //施法者对特定职业加伤
        switch (targetJob) {
            case GDHero.Job.J1:
                damageAddSum += actorAttr.damageAddJ1();
                break;
            case GDHero.Job.J2:
                damageAddSum += actorAttr.damageAddJ2();
                break;
            case GDHero.Job.J3:
                damageAddSum += actorAttr.damageAddJ3();
                break;
            case GDHero.Job.J4:
                damageAddSum += actorAttr.damageAddJ4();
                break;
            default:
                break;
        }
        //目标对特定职业减伤
        switch (actorJob) {
            case GDHero.Job.J1:
                hurtIgnSum += targetAttr.hurtIgnJ1();
                break;
            case GDHero.Job.J2:
                hurtIgnSum += targetAttr.hurtIgnJ2();
                break;
            case GDHero.Job.J3:
                hurtIgnSum += targetAttr.hurtIgnJ3();
                break;
            case GDHero.Job.J4:
                hurtIgnSum += targetAttr.hurtIgnJ4();
                break;
            default:
                break;
        }
        double rate = (damageAddSum - hurtIgnSum) / GD.W_10000_0;
        return 1.0 + Math.max(-0.6, rate);
    }


    /**
     * 阵营伤害系数
     *
     * @param actorCamp
     * @param targetCamp
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    private double calCampRate(byte actorCamp, byte targetCamp, FightAttr actorAttr, FightAttr targetAttr) {
        double damageAddSum = 0;
        double hurtIgnSum = 0;
        //施法者对特定阵营加伤
        switch (targetCamp) {
            case GDCamp.Type.C1:
                damageAddSum += actorAttr.damageAddC1();
                break;
            case GDCamp.Type.C2:
                damageAddSum += actorAttr.damageAddC2();
                break;
            case GDCamp.Type.C3:
                damageAddSum += actorAttr.damageAddC3();
                break;
            case GDCamp.Type.C4:
                damageAddSum += actorAttr.damageAddC4();
                break;
            case GDCamp.Type.C5:
                damageAddSum += actorAttr.damageAddC5();
                break;
            case GDCamp.Type.C6:
                damageAddSum += actorAttr.damageAddC6();
                break;
            default:
                break;
        }
        //目标对特定阵营减伤
        switch (actorCamp) {
            case GDCamp.Type.C1:
                hurtIgnSum += targetAttr.hurtIgnC1();
                break;
            case GDCamp.Type.C2:
                hurtIgnSum += targetAttr.hurtIgnC2();
                break;
            case GDCamp.Type.C3:
                hurtIgnSum += targetAttr.hurtIgnC3();
                break;
            case GDCamp.Type.C4:
                hurtIgnSum += targetAttr.hurtIgnC4();
                break;
            case GDCamp.Type.C5:
                hurtIgnSum += targetAttr.hurtIgnC5();
                break;
            case GDCamp.Type.C6:
                hurtIgnSum += targetAttr.hurtIgnC6();
                break;
            default:
                break;
        }
        double rate = (damageAddSum - hurtIgnSum) / GD.W_10000_0;
        return 1.0 + Math.max(-0.6, rate);
    }




    /**
     * pvp伤害加成系数
     *
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    protected double pvpRate(FightAttr actorAttr, FightAttr targetAttr) {
        double rate = (actorAttr.pvpUp() - targetAttr.pvpDown()) / GD.W_10000_0;
        return 1 + Math.max(-0.8, rate);
    }

    /**
     * pve伤害加成系数
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    protected double pveRate(FightAttr actorAttr, FightAttr targetAttr) {
        double rate = (actorAttr.pveUp() - targetAttr.pveDown()) / GD.W_10000_0;
        return 1 + Math.max(-0.8, rate);
    }


    /**
     * 计算神圣伤害
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    protected double calHolyDamage(FightAttr actorAttr, FightAttr targetAttr) {
        double damage = actorAttr.hollyDamage() - targetAttr.hollyDamageDef();
        return Math.max(0, damage);
    }

    /**
     * 豁免系数（格挡）
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    protected double calParryRate(SkillActionCtx action, Fighter target, FightAttr actorAttr, FightAttr targetAttr) {
        double rate = 1.0d;
        double parryRate = (targetAttr.parryRate() - actorAttr.parryInterference()) / GD.W_10000_0;

        boolean parry = Math.random() < parryRate;
        if (parry) {
            double reduce = targetAttr.parryDamageReduce() / GD.W_10000_0 + 0.3;
            rate = Math.max(0.1, 1 - reduce);
        }
        ActionStat.TargetStat stat = action.getStat().getOrBuildTarget(target.getPid());
        stat.parry = true;
        stat.parryRate = 1-rate;
        return rate;
    }


    /**
     * 计算灵能伤害
     * @param action
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    protected double calPsychicDamage(SkillActionCtx action, FightAttr actorAttr, FightAttr targetAttr) {
        if (!action.getActor().status.isAwaken()) {
            return 0d;
        }
        double value = actorAttr.psyAttTotal() - targetAttr.psyDefTotal();
        double rate = 1 + (actorAttr.psyUp() - targetAttr.psyRes()) / GD.W_10000_0;
        value = Math.max(0, value);
        rate = Math.max(0, rate);
        return value * rate * xsTargetCoeff(action.getTargets().size());
    }

    /**
     * pvp最终增伤
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    protected double pvpFinalRate(FightAttr actorAttr, FightAttr targetAttr) {
        double rate = 1.0d + (actorAttr.pvpFinalDamageAdd() - targetAttr.pvpFinalHurtIgn()) / GD.W_10000_0;
        return Math.max(0.1, rate);
    }

    /**
     * 元素伤害
     * @param actorCamp
     * @param actorAttr
     * @param targetAttr
     * @return
     */
    protected double calElementDamage(byte actorCamp, FightAttr actorAttr, FightAttr targetAttr) {
        double value = actorAttr.elementAttTotal(actorCamp) * totalCoeff / GD.W_10000_0 - targetAttr.elementDef(actorCamp);
        double rate = (1 - targetAttr.elementIgn(actorCamp) / GD.W_10000_0);
        value = Math.max(0, value);
        rate = Math.max(0, rate);
        return value * rate;
    }
}
